package it.koutifaris.travianmap.mapsqlparser;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;

import org.apache.commons.io.input.CountingInputStream;

import android.util.Log;

public abstract class AbstractMapSqlParser implements MapSqlParser {

	protected final String TAG = this.getClass().getName();

	protected abstract MapSqlEntry parseLine(String line) throws Exception;

	@Override
	public final void parse(RemoteSource remoteSource, MapSqlEntryHandler handler) throws SqlParserException {
		parse(remoteSource, handler, NullProgressHandler.nullProgressHandler());
	}

	@Override
	public final void parse(RemoteSource remoteSource, MapSqlEntryHandler handler, ProgressHandler progressHandler)
			throws SqlParserException {
		try {
			internalParse(remoteSource, handler, progressHandler);
		} catch (IOException e) {
			Log.e(TAG, e.getMessage());
			handler.onFail(e);
			throw new SqlParserException("IOException while reading", e);
		} catch (Exception e) {
			Log.e(TAG, "" + e.getMessage());
			handler.onFail(e);
			throw new SqlParserException("Unexpected error while reading", e);
		}
	}

	private void internalParse(RemoteSource remoteSource, MapSqlEntryHandler handler, ProgressHandler progressHandler) throws Exception {
		CountingStreamWrapper countingStreamWrapper = new CountingStreamWrapper();
		InputStream sourceStream = remoteSource.sourceStream(countingStreamWrapper);
		CountingInputStream countingInputStream = countingStreamWrapper.getCountingInputStream();
		BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(sourceStream, Charset.forName("UTF-8")));

		String line;

		handler.init(remoteSource.lastModified());
		long readStart = System.nanoTime();
		long readTime = 0;

		long parseTime = 0;

		long onEntryTime = 0;

		while ((line = bufferedReader.readLine()) != null) {
			readTime += System.nanoTime() - readStart;
			readStart = System.nanoTime();

			long parseStart = System.nanoTime();
			MapSqlEntry entry = parseLine(line);
			parseTime += System.nanoTime() - parseStart;

			long onEntryStart = System.nanoTime();
			boolean stop = !handler.onEntry(entry);
			onEntryTime += System.nanoTime() - onEntryStart;
			progressHandler.onProgress(countingInputStream.getByteCount());

			if (stop) {
				break;
			}
		}
		handler.done();
		progressHandler.onFinish(countingInputStream.getByteCount());

		bufferedReader.close();

		Log.i(TAG, "Read time: " + readTime / 1000000);
		Log.i(TAG, "Parse time: " + parseTime / 1000000);
		Log.i(TAG, "OnEntry time: " + onEntryTime / 1000000);
	}
}
